# coding=utf-8

import json
import logging
import traceback
import urllib.request, urllib.parse, urllib.error

from django.core.cache import cache
from django.shortcuts import redirect
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

from lib.common import AbstractHandler, CacheKeys
from lib.wxpay.wxpay import WeChatPay
from project.settings import wx_settings
# from services.datamodel.product.models import WeChatTrade, mm_WeChatTrade, mm_Product, mm_ProductPurchase
from datetime import datetime

from services.datamodel.order.models import Order, mm_Order
from services.datamodel.student.models import mm_Student

wechat_logger = logging.getLogger("wechat")


class WX_Handler(AbstractHandler):
    def __init__(self):
        AbstractHandler.__init__(self, logging.getLogger("django"))

        self.METHOD_TAB = {
            'GET': {
                'wx_authorize': self.handle_authorize,
                'get_oid': self.handle_wx_get_oid_and_info,
            }
        }

    WX_USER_AUTHORIZE = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + wx_settings.APP_ID + \
                        '&redirect_uri=http%3A%2F%2F<domain>%2Fapi%2Fpayment%2Fwx%2F%3Faction%3Dget_oid&' \
                            .replace('<domain>', wx_settings.WX_AHTH_REDIRECT_DOMAIN) + \
                        'response_type=code&scope=snsapi_userinfo&state=<state>#wechat_redirect'
    WX_GET_USER_OID_URL_FMT = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code'
    WX_GET_USER_INFO_URL_FMT = 'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN'

    PHONE_HTML_TMPLT = '''
    <!DOCTYPE html><html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
    </head>
    <body><div style='margin: 20% 5%;text-align: center;font-size: x-large;color:#127A88;'>
    %s</div>
    </body></html>
    '''

    PHONE_HTML_WX_AUTHOR_OK = '''
    <!DOCTYPE html><html>
    <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
    </head>
    <body><div><img style="width: 100%"  src="http://cdn-ali-static.zgyjyx.com/etc/others/wx_authorize_ok.png"></div></body></html>
    '''

    # 该请求是从用户微信扫描二维码 发起的访问， 需要重定向到腾讯服务器
    def handle_authorize(self, request):
        # 获取该用户信息缓存的key，下面要用到
        self.checkMandatoryParams(request, ['ck'])
        usercachekey = request.param_dict['ck']

        url = self.WX_USER_AUTHORIZE.replace('<state>', usercachekey)
        # print 'redirect to  ' + url
        return redirect(url)

    # 该请求是从用户微信从 腾讯服务器 重定向返回到 我们服务器 的访问，
    # 为什么放在common里面呢？ 没有办法，因为微信浏览器用户并没有登录我们系统
    # 这里就是为了给没有登录的请求使用的，不然就放在各种用户的app的 handler 里面了
    def handle_wx_get_oid_and_info(self, request):

        # 第一步 用户同意授权，获取code后，去获取access token，openid，state字段用来保存用户的ID
        self.checkMandatoryParams(request, ['code', 'state'])
        code = request.param_dict['code']
        getTokenUrl = self.WX_GET_USER_OID_URL_FMT % (wx_settings.APP_ID,
                                                      wx_settings.APP_SECRET,
                                                      code)

        # print 'getTokenUrl ' + getTokenUrl
        r = urllib.request.urlopen(getTokenUrl)
        content = r.read()
        retObj = json.loads(content)

        if 'openid' not in retObj:
            return HttpResponse(self.PHONE_HTML_TMPLT % '不能获取用户openid')
        if 'access_token' not in retObj:
            return HttpResponse(self.PHONE_HTML_TMPLT % '不能获取用户access_token')

        oid = retObj['openid']
        access_token = retObj['access_token']

        # print 'oid: %s' % oid
        # print 'access_token: %s' % access_token

        # 第二步 得到access token，openid，并 根据它们 获取用户信息

        getInfoUrl = self.WX_GET_USER_INFO_URL_FMT % (access_token, oid)
        r = urllib.request.urlopen(getInfoUrl)
        content = r.read()
        retObj = json.loads(content)
        # print retObj

        if 'nickname' not in retObj:
            return HttpResponse(self.PHONE_HTML_TMPLT % '获取用户信息失败')

        # 第三步 用户信息放入缓存，等待前端来主动获取
        ck = request.param_dict['state']
        cacheKey = CacheKeys.wx_userinfo % ck

        # print 'set cacheKey' + cacheKey
        cache.set(cacheKey, retObj, 300)

        return HttpResponse(self.PHONE_HTML_WX_AUTHOR_OK)

        # return HttpResponse(self.PHONE_HTML_TMPLT % u'微信授权成功<br><br>有效期5分钟<br><br>请在网页上点击 "确认微信帐号" ')

    @csrf_exempt
    def handle_wechat_mobile_notify(self, request, user_type):
        try:
            client_ip = self.get_client_ip(request)
            pay_settings = dict(wx_settings._pay_tuple)
            if user_type not in list(pay_settings.keys()):
                wechat_logger.warning("!!got an invalid wechat notify from:%s" % client_ip)
                return HttpResponse()

            mch_key = pay_settings[user_type]['key']
            # 校验签名是否正确
            checkresult, xmldata = WeChatPay.verify_notify_string(request.body, mch_key)
            # checkresult, xmldata = True, {'appid': 'wx76a6f46b670c4e92', 'bank_type': 'CFT', 'cash_fee': '10',
            # 'device_info': 'WEB', 'fee_type': 'CNY', 'is_subscribe': 'Y', 'mch_id': '1498739252',
            # 'nonce_str': '5JYM4LAOPQVCI960KSD8N3FTXH217WGB', 'openid': 'otynd0-RFZWnw6XfrGL44yQ8TEBE',
            # 'out_trade_no': '333_1560241561_6_57_0', 'result_code': 'SUCCESS', 'return_code': 'SUCCESS',
            # 'time_end': '20190611162546', 'total_fee': '10', 'trade_type': 'JSAPI',
            # 'transaction_id': '4200000315201906112439969357'}

            wechat_logger.info('wechat recall result: %s, xmldata: %s' % (checkresult, xmldata))
            if checkresult:
                result_code = xmldata['result_code']
                return_code = xmldata['return_code']
                resultparm = {'return_code': 'SUCCESS', 'return_msg': 'OK'}
                returnwechat = WeChatPay.dict_to_xml(resultparm).encode('utf-8')
                if return_code == 'SUCCESS':
                    # 使用内部订单，以及金额来进一步校验请求的合法性
                    wechatorder = mm_Order.filter(order_no=xmldata['out_trade_no'], charge=xmldata['total_fee']).first()
                    # wechatorder = mm_WeChatTrade.get(tradeno_yijiao=xmldata['out_trade_no'],
                    #                                  total_fee='%.2f' % (float(xmldata['total_fee']) / 100))
                    # wechatorder.return_msg = xmldata.get('return_msg', '')
                    # wechatorder.err_code = xmldata.get('err_code', '')
                    # wechatorder.err_code_des = xmldata.get('err_code_des', '')
                    # # if success
                    if result_code == 'SUCCESS':
                        # 商户订单号
                        # 如果此时订单已经是Payed状态，那么直接返回即可，因为微信会重复推送，直到服务端返回其正确的指示
                        if wechatorder.status == 2:
                            return HttpResponse(returnwechat, content_type='application/xml')
                        mm_Order.unproxybycard(wechatorder)
                        # wechatorder.deal_status = mm_WeChatTrade.TRADE_STATUS_PAYED
                        # wechatorder.trade_type = xmldata['trade_type']
                        # wechatorder.bank_type = xmldata['bank_type']
                        # wechatorder.fee_type = xmldata['fee_type']
                        # wechatorder.tradeno_wx = xmldata['transaction_id']
                        # # 支付完成时间
                        # wechatorder.time_end = xmldata['time_end']
                        # wechatorder.save()
                        return HttpResponse(returnwechat, content_type='application/xml')
                else:
                    # if false do nothing
                    pass
            else:
                return HttpResponse('未认证支付请求', content_type='application/json')
        except Order.DoesNotExist:
            wechat_logger.warning("!!missing out_trade_no in our system: %s" % xmldata['out_trade_no'])
            return HttpResponse()


wxpay_handler = WX_Handler()
